package com.fan.shop.businesslogic;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

import org.apache.log4j.Logger;

import com.fan.shop.domain.PurchaseLine;
import com.fan.shop.domain.PurchaseOrder;
import com.fan.shop.global.ShopGlobalVariables;
import com.fan.shop.model.userclass.PurchaseLineUserClass;
import com.fan.shop.process.ProcExec;
import com.fan.shop.services.ItemService;
import com.fan.shop.services.PurchaseLineService;
import com.fan.shop.services.PurchaseOrderService;
import com.fan.shop.services.StockService;
import com.fan.shop.services.StoreService;
import com.fan.shop.services.TransactionReferenceService;
import com.fan.shop.services.UserService;

public class PurchaseOrderUpdateProcess extends ProcExec<Integer> {

	private static Logger logger = Logger
			.getLogger(PurchaseOrderUpdateProcess.class);
	private PurchaseOrderService purchaseOrderService;
	private PurchaseLineService purchaseLineService;
	private UserService userService;
	private StoreService storeService;
	private StockService stockService;

	private ItemService itemService;
	private TransactionReferenceService transactionReferenceService;

	private String poNumber;
	private String transactionCode;
	private String officerCode;
	private String storeCode;
	private Date transactionDate;
	private BigDecimal postage;
	private String status;
	private String buyer;
	private String deliveryAddress;
	private String comments;

	private List<PurchaseLineUserClass> attachedPOLines;

	public static Logger getLogger() {
		return logger;
	}

	public static void setLogger(Logger logger) {
		PurchaseOrderUpdateProcess.logger = logger;
	}

	public PurchaseOrderService getPurchaseOrderService() {
		return purchaseOrderService;
	}

	public void setPurchaseOrderService(
			PurchaseOrderService purchaseOrderService) {
		this.purchaseOrderService = purchaseOrderService;
	}

	public PurchaseLineService getPurchaseLineService() {
		return purchaseLineService;
	}

	public void setPurchaseLineService(PurchaseLineService purchaseLineService) {
		this.purchaseLineService = purchaseLineService;
	}

	public UserService getUserService() {
		return userService;
	}

	public void setUserService(UserService userService) {
		this.userService = userService;
	}

	public StoreService getStoreService() {
		return storeService;
	}

	public void setStoreService(StoreService storeService) {
		this.storeService = storeService;
	}

	public ItemService getItemService() {
		return itemService;
	}

	public void setItemService(ItemService itemService) {
		this.itemService = itemService;
	}

	public String getPoNumber() {
		return poNumber;
	}

	public void setPoNumber(String poNumber) {
		this.poNumber = poNumber;
	}

	public String getTransactionCode() {
		return transactionCode;
	}

	public void setTransactionCode(String transactionCode) {
		this.transactionCode = transactionCode;
	}

	public String getOfficerCode() {
		return officerCode;
	}

	public void setOfficerCode(String officerCode) {
		this.officerCode = officerCode;
	}

	public String getStoreCode() {
		return storeCode;
	}

	public void setStoreCode(String storeCode) {
		this.storeCode = storeCode;
	}

	public Date getTransactionDate() {
		return transactionDate;
	}

	public void setTransactionDate(Date transactionDate) {
		this.transactionDate = transactionDate;
	}

	public StockService getStockService() {
		return stockService;
	}

	public void setStockService(StockService stockService) {
		this.stockService = stockService;
	}

	public TransactionReferenceService getTransactionReferenceService() {
		return transactionReferenceService;
	}

	public void setTransactionReferenceService(
			TransactionReferenceService transactionReferenceService) {
		this.transactionReferenceService = transactionReferenceService;
	}

	public BigDecimal getPostage() {
		return postage;
	}

	public void setPostage(BigDecimal postage) {
		this.postage = postage;
	}

	public String getStatus() {
		return status;
	}

	public void setStatus(String status) {
		this.status = status;
	}

	public String getBuyer() {
		return buyer;
	}

	public void setBuyer(String buyer) {
		this.buyer = buyer;
	}

	public String getDeliveryAddress() {
		return deliveryAddress;
	}

	public void setDeliveryAddress(String deliveryAddress) {
		this.deliveryAddress = deliveryAddress;
	}

	public String getComments() {
		return comments;
	}

	public void setComments(String comments) {
		this.comments = comments;
	}

	public List<PurchaseLineUserClass> getAttachedPOLines() {
		return attachedPOLines;
	}

	public void setAttachedPOLines(List<PurchaseLineUserClass> attachedPOLines) {
		this.attachedPOLines = attachedPOLines;
	}

	private int validatePurchaseOrder() {
		PurchaseOrderValidateProcess purchaseOrderValidateProcess = new PurchaseOrderValidateProcess();
		purchaseOrderValidateProcess.setPoNumber(poNumber);
		purchaseOrderValidateProcess.setOfficerCode(officerCode);
		purchaseOrderValidateProcess.setStoreCode(storeCode);
		purchaseOrderValidateProcess.setTransactionCode(transactionCode);
		purchaseOrderValidateProcess.setPostage(postage);
		purchaseOrderValidateProcess.setBuyer(buyer);
		purchaseOrderValidateProcess.setDeliveryAddress(deliveryAddress);
		purchaseOrderValidateProcess.setAttachedPOLines(attachedPOLines);
		purchaseOrderValidateProcess
				.setPurchaseOrderService(purchaseOrderService);
		purchaseOrderValidateProcess
				.setPurchaseLineService(purchaseLineService);
		purchaseOrderValidateProcess.setUserService(userService);
		purchaseOrderValidateProcess.setStoreService(storeService);
		purchaseOrderValidateProcess.setStockService(stockService);
		purchaseOrderValidateProcess.setItemService(itemService);
		purchaseOrderValidateProcess
				.setTransactionReferenceService(transactionReferenceService);
		purchaseOrderValidateProcess.setStatus(status);
		return purchaseOrderValidateProcess.process();
	}

	@Override
	public Integer processImpl() {
		if (validatePurchaseOrder() == ShopGlobalVariables.FAILED) {
			setErrorMessage("Validation failed");
			return ShopGlobalVariables.FAILED;
		}

		if (status.equals(ShopGlobalVariables.CANCELLED)) {
			setErrorMessage("Purchase Order: " + poNumber
					+ " cannot be modified in Cancelled status");
			return ShopGlobalVariables.FAILED;
		} else {
			PurchaseOrder purchaseOrder = purchaseOrderService
					.getPurchaseOrder(poNumber);
			purchaseOrder.setOfficerCode(officerCode);
			purchaseOrder.setStoreCode(storeCode);
			purchaseOrder.setTransactionCode(transactionCode);
			purchaseOrder.setTransactionDate(transactionDate);
			purchaseOrder.setStatus(status);
			purchaseOrder.setPostage(postage);
			purchaseOrder.setComments(comments);
			purchaseOrder.setBuyer(buyer);
			purchaseOrder.setDeliveryAddress(deliveryAddress);

			for (PurchaseLineUserClass purchaseLineUserClass : attachedPOLines) {
				String itemCode = purchaseLineUserClass.getItemCode();

				// validate stock
				PurchaseOrderLineValideProcess purchaseOrderLineValideProcess = new PurchaseOrderLineValideProcess();
				purchaseOrderLineValideProcess.setItemService(itemService);
				purchaseOrderLineValideProcess
						.setPurchaseLineService(purchaseLineService);
				purchaseOrderLineValideProcess.setStockService(stockService);
				purchaseOrderLineValideProcess.setStoreService(storeService);
				purchaseOrderLineValideProcess.setPoNumber(poNumber);
				purchaseOrderLineValideProcess
						.setItemCode(purchaseLineUserClass.getItemCode());
				purchaseOrderLineValideProcess.setStoreCode(storeCode);
				purchaseOrderLineValideProcess
						.setPurchaseLineUserClass(purchaseLineUserClass);
				purchaseOrderLineValideProcess.setStatus(status);
				int result = purchaseOrderLineValideProcess.process();

				if (result == ShopGlobalVariables.FAILED) {
					setErrorMessage(purchaseOrderLineValideProcess
							.getErrorMessage());
					return ShopGlobalVariables.FAILED;
				}

				// update existing po line
				if (purchaseLineService.hasPurchaseLine(poNumber, itemCode)) {

					PurchaseLine origPurchaseLine = purchaseLineService
							.getPurchaseLine(poNumber, itemCode);
					int origLineQty = origPurchaseLine.getQuantity();

					PurchaseOrderLineUpdateProcess purchaseOrderLineUpdateProcess = new PurchaseOrderLineUpdateProcess();
					purchaseOrderLineUpdateProcess.setPoNumber(poNumber);
					purchaseOrderLineUpdateProcess.setItemCode(itemCode);
					purchaseOrderLineUpdateProcess
							.setPrice(purchaseLineUserClass.getPrice());
					purchaseOrderLineUpdateProcess.setQty(purchaseLineUserClass
							.getQuantity());
					purchaseOrderLineUpdateProcess
							.setPurchaseLineService(purchaseLineService);

					// update stock
					StockHoldQtyUpdateProcess stockHoldQtyUpdateProcess = new StockHoldQtyUpdateProcess();
					stockHoldQtyUpdateProcess.setItemCode(purchaseLineUserClass
							.getItemCode());
					stockHoldQtyUpdateProcess.setStoreCode(storeCode);
					stockHoldQtyUpdateProcess.setStockService(stockService);

					int qtyDiff = purchaseLineUserClass.getQuantity()
							- origLineQty;

					stockHoldQtyUpdateProcess.setPoQuantity(qtyDiff);

					result = stockHoldQtyUpdateProcess.process();
					if (result == ShopGlobalVariables.FAILED) {
						setErrorMessage(stockHoldQtyUpdateProcess
								.getErrorMessage());
						return result;
					} else {
						result = purchaseOrderLineUpdateProcess.process();
						if (result == ShopGlobalVariables.FAILED) {
							setErrorMessage(purchaseOrderLineUpdateProcess
									.getErrorMessage());
							return ShopGlobalVariables.FAILED;
						}
					}

				}
				// insert new po line
				else {
					PurchaseOrderLineCreateProcess purchaseOrderLineCreateProcess = new PurchaseOrderLineCreateProcess();
					purchaseOrderLineCreateProcess.setPoNumber(poNumber);
					purchaseOrderLineCreateProcess.setItemCode(itemCode);
					purchaseOrderLineCreateProcess
							.setPrice(purchaseLineUserClass.getPrice());
					purchaseOrderLineCreateProcess.setQty(purchaseLineUserClass
							.getQuantity());
					purchaseOrderLineCreateProcess
							.setPurchaseLineService(purchaseLineService);
					result = purchaseOrderLineCreateProcess.process();
					if (result == ShopGlobalVariables.FAILED) {
						setErrorMessage(purchaseOrderLineCreateProcess
								.getErrorMessage());
						return ShopGlobalVariables.FAILED;
					} else {
						StockHoldQtyUpdateProcess stockHoldQtyUpdateProcess = new StockHoldQtyUpdateProcess();
						stockHoldQtyUpdateProcess
								.setItemCode(purchaseLineUserClass
										.getItemCode());
						stockHoldQtyUpdateProcess.setStoreCode(storeCode);
						stockHoldQtyUpdateProcess.setStockService(stockService);
						stockHoldQtyUpdateProcess
								.setPoQuantity(purchaseLineUserClass
										.getQuantity());

						result = stockHoldQtyUpdateProcess.process();
						if (result == ShopGlobalVariables.FAILED) {
							setErrorMessage(stockHoldQtyUpdateProcess
									.getErrorMessage());
							return result;
						}
					}

				}
			}
			try {
				purchaseOrderService.updatePurchaseOrder(purchaseOrder);
			} catch (Exception e) {
				e.printStackTrace();
				setErrorMessage(e.getMessage());
				return ShopGlobalVariables.FAILED;
			}
		}

		return ShopGlobalVariables.SUCCESS;
	}
}
